/*
 Any copyright to this file is released to the Public Domain.
 http://creativecommons.org/publicdomain/zero/1.0/
 If you like this, you should donate
 to Peter O. (original author of
 the Public Domain HTML 3D Library) at:
 http://peteroupc.github.io/
*/
/* global H3DU */

/**
 * A [surface evaluator object]{@link H3DU.Surface} for a surface of revolution,
 * which results by revolving
 * a two-dimensional curve around an axis.
 * <p>This class is considered a supplementary class to the
 * Public Domain HTML 3D Library and is not considered part of that
 * library. <p>
 * To use this class, you must include the script "extras/evaluators.js"; the
 * class is not included in the "h3du_min.js" file which makes up
 * the HTML 3D Library. Example:<pre>
 * &lt;script type="text/javascript" src="extras/evaluators.js">&lt;/script></pre>
 * @constructor
 * @memberof H3DU
 * @param {Object} curve A [curve evaluator object]{@link H3DU.Curve} that describes a 2-dimensional curve to rotate about the axis of rotation, as
 * specified in the "axis" parameter. The curve's X coordinates
 * correspond to elevation, and its Y coordinates correspond to radius.<p>
 * If the curve function draws a curve that goes both above and below the axis of rotation, such
 * as a circle or ellipse, the V coordinates given in _minval_ and _maxval_ must
 * restrict the curve definition to no more than half of the curve.
 * @param {number} minval Smallest V coordinate.
 * @param {number} maxval Largest V coordinate. If _minval_ is greater than
 * _maxval_, both values will be swapped.
 * @param {Array<number>} [axis] Axis of rotation, around which the curve
 * will be rotated to generate the surface of revolution. If null, undefined, or omitted, the positive
 * Z axis (0, 0, 1) will be the axis of rotation. This parameter is a 3-element array describing
 * the X, Y, and Z coordinates, respectively, of a 3D point. The axis of rotation will
 * run in the direction from the origin to the point given in this parameter. This
 * parameter need not be a [unit vector]{@tutorial glmath}.
 */
H3DU.SurfaceOfRevolution = function(curve, minval, maxval, axis) {
  "use strict";
  this.curve = curve;
  this.minval = Math.min(minval, maxval);
  this.maxval = Math.max(minval, maxval);
  this._axis = axis;
  this._axisQuat = null;
  if(this._axis) {
    this._axisQuat = H3DU.Math.quatFromVectors([0, 0, 1], this._axis);
  }
};
H3DU.SurfaceOfRevolution.prototype = Object.create(H3DU.Surface.prototype);
H3DU.SurfaceOfRevolution.prototype.constructor = H3DU.SurfaceOfRevolution;
/** @inheritdoc */
H3DU.SurfaceOfRevolution.prototype.endPoints = function() {
  "use strict";
  return [0, H3DU.Math.PiTimes2, this.minval, this.maxval];
};
/**
 * Finds the coordinates of the given point of this surface.
 * @param {number} u U coordinate of the surface to evaluate.
 * @param {number} v V coordinate of the surface to evaluate.
 * @returns {Array<number>} An array containing the coordinates
 * of the position at the given point. It will have three elements.
 */
H3DU.SurfaceOfRevolution.prototype.evaluate = function(u, v) {
  "use strict";
  var curvepos = this.curve.evaluate(v);
  var cosu = Math.cos(u);
  var sinu = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(u);
  var cp1 = curvepos[1];
  var cp0 = curvepos[0];
  var x = cp1 * cosu;
  var y = cp1 * sinu;
  var z = cp0;
  var ret = [x, y, z];
  if(this._axisQuat) {
    H3DU.SurfaceOfRevolution._quatTransformInPlace(this._axisQuat, ret);
  }
  return ret;
};
/** @ignore */
H3DU.SurfaceOfRevolution._quatTransformInPlace = function(q, v) {
  "use strict";
  var t1 = q[1] * v[2] - q[2] * v[1] + v[0] * q[3];
  var t2 = q[2] * v[0] - q[0] * v[2] + v[1] * q[3];
  var t3 = q[0] * v[1] - q[1] * v[0] + v[2] * q[3];
  var t4 = q[0] * v[0] + q[1] * v[1] + q[2] * v[2];
  v[0] = t1 * q[3] - (t2 * q[2] - t3 * q[1]) + q[0] * t4;
  v[1] = t2 * q[3] - (t3 * q[0] - t1 * q[2]) + q[1] * t4;
  v[2] = t3 * q[3] - (t1 * q[1] - t2 * q[0]) + q[2] * t4;
};
/**
 * Creates a [surface evaluator object]{@link H3DU.Surface} for a surface of revolution
 * whose curve is the graph of a single-variable function.
 * The resulting surface will have a circular cross section
 * along its length.
 * Examples of surfaces generated by this technique are
 * cones, frustums, cylinders, spheres, and spheroids (the
 * bases of these surfaces won't be generated).
 * @param {Function} func Function whose graph will be
 * rotated about the axis of rotation, as
 * specified in the "axis" parameter. The function takes a number
 * as a single parameter and returns a number. The return
 * value is effectively the radius of each part of the surface
 * from beginning to end.
 * @param {number} minval Smallest parameter of the function.
 * This is a number of units from the origin along the axis of rotation.
 * @param {number} maxval Largest parameter of the function.
 * This is a number of units from the origin along the axis of rotation.
 * If _minval_ is greater than _maxval_, both values will be swapped.
 * @param {Array<number>} [axis] Axis of rotation, around which the
 * function graph will be rotated to generate the surface of revolution.
 * If null, undefined, or omitted, the positive Z axis (0, 0, 1) will be the axis of rotation.
 * This parameter is a 3-element array describing
 * the X, Y, and Z coordinates, respectively, of a 3D point. The axis of rotation will
 * run in the direction from the origin to the point given in this parameter. This
 * parameter need not be a [unit vector]{@tutorial glmath}.
 * @returns {H3DU.SurfaceOfRevolution} Return value.
 * @example <caption>The following creates an evaluator for a cone
 * which starts at the origin and runs 10 units along the Z axis.</caption>
 * var surf=H3DU.SurfaceOfRevolution.fromFunction(
 * function(x) {
 * "use strict"; return x/2; }, // use a constantly increasing function
 * 0, 10);
 * @example <caption>This is an evaluator for the same cone, but
 * shifted 3 units back.</caption>
 * var surf=H3DU.SurfaceOfRevolution.fromFunction(
 * function(x) {
 * "use strict"; x+=3; return x/2; },
 * -3,7);
 * @example <caption>The following creates an evaluator for a cylinder
 * which runs from 5 to 10 units, and with a radius of 2 units.</caption>
 * var surf=H3DU.SurfaceOfRevolution.fromFunction(
 * function(x) {
 * "use strict"; return 2; }, // use a constant radius
 * 5, 10);
 */
H3DU.SurfaceOfRevolution.fromFunction = function(func, minval, maxval, axis) {
  "use strict";
  return new H3DU.SurfaceOfRevolution({
    "evaluate":function(u) {
      return [u, func(u), 0];
    }
  }, minval, maxval, axis);
};
/**
 * A [surface evaluator object]{@link H3DU.Surface} for a torus, a special case of a surface of revolution.
 * @param {number} outerRadius Radius from the center to the innermost
 * part of the torus.
 * @param {number} innerRadius Radius from the inner edge to the innermost
 * part of the torus.
 * @param {Object} [curve] A [curve evaluator object]{@link H3DU.Curve} that
 * describes a 2-dimensional curve to serve as
 * the cross section of the torus. The curve need not be closed; in fact, certain special surfaces can result
 * by leaving the ends open.
 * If null, undefined, or omitted, uses a circular cross section with a radius of 1.
 * @param {Array<number>} [axis] Axis of rotation, which the torus
 * will pass through.
 * If null, undefined, or omitted, the positive Z axis (0, 0, 1) will be the axis of rotation.
 * This parameter is a 3-element array describing
 * the X, Y, and Z coordinates, respectively, of a 3D point. The axis of rotation will
 * run in the direction from the origin to the point given in this parameter. This
 * parameter need not be a [unit vector]{@tutorial glmath}.
 * @returns {H3DU.SurfaceOfRevolution} Return value.
 */
H3DU.SurfaceOfRevolution.torus = function(outerRadius, innerRadius, curve, axis) {
  "use strict";
  if(!curve)curve = {
    "evaluate":function(u) {
      var cosu = Math.cos(u);
      var sinu = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(u);
      return [cosu, sinu];
    },
    "velocity":function(u) {
      var cosu = Math.cos(u);
      var sinu = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(u);
      return [-sinu, cosu];
    }
  };
  return new H3DU.SurfaceOfRevolution({
    "evaluate":function(u) {
      var curvept = curve.evaluate(u);
      var x = innerRadius * curvept[1];
      var y = outerRadius + innerRadius * curvept[0];
      return [x, y, 0];
    },
    "endPoints":function() {
      return [0, H3DU.Math.PiTimes2];
    }
  }, 0, H3DU.Math.PiTimes2, axis);
};

/* exported SurfaceOfRevolution */
/**
 * Alias for the {@link H3DU.SurfaceOfRevolution} class.
 * @constructor
 * @alias SurfaceOfRevolution
 * @deprecated Use {@link H3DU.SurfaceOfRevolution} instead.
 */
var SurfaceOfRevolution = H3DU.SurfaceOfRevolution;
/**
 * A [curve evaluator object]{@link H3DU.Curve} for a curve drawn by a circle that rolls along the inside
 * of another circle, whose position is fixed, with a center of (0,0).<p>
 * The following curves can be generated with this class (in the following
 * descriptions, O = <code>outerRadius</code>, R means <code>innerRadius</code>,
 * and D = <code>distFromRollerCenter</code>).<ul>
 * <li>Hypocycloid: D = R (hypotrochoid touching the fixed circle).</li>
 * <li>Curtate hypocycloid: D < R (hypotrochoid not touching the fixed circle).</li>
 * <li>Prolate hypocycloid: D > R (hypotrochoid crossing the fixed circle).</li>
 * <li>Circle: O = R*2; the circle will have radius R - D.</li>
 * <li>Ellipse: O = R*2; the ellipse (unrotated) will have width abs(R+D)*2
 * and height abs(R-D)*2.</li>
 * <li>Line segment with length O*2: O = R*2; D = R.</li>
 * <li>Deltoid: O = R*3; D = R.</li>
 * <li>Astroid: O = R*4; D = R.</li>
 * <li>N-pointed hypocycloid: O = R * N; D = R.</li></ul>
 * <p>This class is considered a supplementary class to the
 * Public Domain HTML 3D Library and is not considered part of that
 * library. <p>
 * To use this class, you must include the script "extras/evaluators.js"; the
 * class is not included in the "h3du_min.js" file which makes up
 * the HTML 3D Library. Example:<pre>
 * &lt;script type="text/javascript" src="extras/evaluators.js">&lt;/script></pre>
 * @constructor
 * @augments H3DU.Curve
 * @param {number} outerRadius Radius of the circle whose position
 * is fixed.
 * @param {number} innerRadius Radius of the rolling circle.
 * A hypocycloid results when distFromInnerCenter=innerRadius.
 * @param {number} distFromInnerCenter Distance from the center of the
 * rolling circle to the drawing pen.
 * @param {number} [rotationDegrees] Starting angle of the curve from the positive X axis toward the positive Y axis, in degrees. Default is 0.
 */
H3DU.Hypotrochoid = function(outerRadius, innerRadius, distFromInnerCenter, rotationDegrees) {
  "use strict";
  this.outer = outerRadius;
  this.inner = innerRadius;
  this.distFromInner = distFromInnerCenter;
  var phase = rotationDegrees || 0;
  phase = phase >= 0 && phase < 360 ? phase : phase % 360 +
       (phase < 0 ? 360 : 0);
  phase *= H3DU.Math.ToRadians;
  var cosPhase = Math.cos(phase);
  var sinPhase = phase <= 3.141592653589793 ? Math.sqrt(1.0 - cosPhase * cosPhase) : -Math.sqrt(1.0 - cosPhase * cosPhase);
  this.sinPhase = sinPhase;
  this.cosPhase = cosPhase;
};
H3DU.Hypotrochoid.prototype = Object.create(H3DU.Curve.prototype);
H3DU.Hypotrochoid.prototype.constructor = H3DU.Hypotrochoid;

/**
 * Finds the coordinates of a point on the curve from the given U coordinate.
 * @function
 * @param {number} u U coordinate.
 * @returns {Array<number>} A 3-element array specifying a 3D point.
 * Only the X and Y coordinates can be other than 0.
 */
H3DU.Hypotrochoid.prototype.evaluate = function(u) {
  "use strict";
  var oi = this.outer - this.inner;
  var term = oi * u / this.inner;
  var uangle = u;
  var cosu = Math.cos(uangle),
    sinu = uangle >= 0 && uangle < 6.283185307179586 ? uangle <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(uangle);
  var cost = Math.cos(term),
    sint = term >= 0 && term < 6.283185307179586 ? term <= 3.141592653589793 ? Math.sqrt(1.0 - cost * cost) : -Math.sqrt(1.0 - cost * cost) : Math.sin(term);
  var x = oi * cosu + this.distFromInner * cost;
  var y = oi * sinu - this.distFromInner * sint;
  return [x * this.cosPhase - y * this.sinPhase,
    y * this.cosPhase + x * this.sinPhase, 0];
};
/**
 * Gets the endpoints of this curve.
 * For this curve evaluator object, the curve
 * starts at 0 and ends at &pi;*2.
 * @function
 * @returns {Array<number>} An array containing the two
 * endpoints of the curve. The first number is the start of the curve,
 * and the second number is the end of the curve.
 */
H3DU.Hypotrochoid.prototype.endPoints = function() {
  "use strict";
  return [0, H3DU.Math.PiTimes2];
};
/**
 * Creates a modified version of this curve so that it
 * fits the given radius.
 * @function
 * @param {number} radius Desired radius of the curve.
 * @returns {H3DU.Hypotrochoid} Return value.
 */
H3DU.Hypotrochoid.prototype.scaleTo = function(radius) {
  "use strict";
  var oi = this.outer - this.inner;
  var mx = Math.abs(Math.max(
    -oi - this.distFromInner,
    -oi + this.distFromInner,
    oi - this.distFromInner,
    oi + this.distFromInner));
  var ratio = radius / mx;
  return new H3DU.Hypotrochoid(
    this.outer * ratio,
    this.inner * ratio,
    this.distFromInner * ratio);
};
/**
 * Finds an approximate arc length (distance) between the start of this
 * curve and the point at the given U coordinate of this curve.
 * @param {number} u U coordinate of a point on the curve.
 * @returns {Array<number>} The approximate arc length of this curve at the given U coordinate.
 */
H3DU.Hypotrochoid.prototype.arcLength = function(u) {
  "use strict";
  var b = this.inner - this.distFromInner;
  if(b === 0) {
    // Hypocycloid; drawing pen is at center of inner circle
    var x = 8 * (this.outer - this.inner) * this.inner;
    var s = Math.sin(this.outer * u / (4 * this.inner));
    return x * s * s / this.outer;
  }
  var that = this;
  return new H3DU.Curve({
    "evaluate":function(u) {
      return that.evaluate(u);
    },
    "endPoints":function() {
      return that.endPoints();
    }
  }).arcLength(u);
};

/**
 * Creates a [curve evaluator object]{@link H3DU.Curve} for a rose, a special
 * form of hypotrochoid.
 * @param {number} n Parameter that determines the petal form of the rose.
 * For example, the rose is symmetrical if this number is even.
 * @param {number} distFromInnerCenter Distance from the center of the
 * rolling circle to the drawing pen.
 * @param {number} [rotationDegrees] Starting angle of the curve from the positive X axis toward the positive Y axis, in degrees. Default is 0.
 * @returns {H3DU.Hypotrochoid} The resulting curve evaluator object.
 */
H3DU.Hypotrochoid.rose = function(n, distFromInnerCenter, rotationDegrees) {
  "use strict";
  var denom = n + 1;
  return new H3DU.Hypotrochoid(2 * n * distFromInnerCenter / denom,
    distFromInnerCenter * (n - 1) / denom, distFromInnerCenter, rotationDegrees);
};
/**
 * A [curve evaluator object]{@link H3DU.Curve} for a curve drawn by a circle that rolls along the X axis.
 * <p>
 * The following curves can be generated with this class (in the following
 * descriptions, R means <code>radius</code>
 * and D = <code>distFromCenter</code>).<ul>
 * <li>Cycloid: D = R (trochoid touching the fixed circle).</li>
 * <li>Curtate cycloid: D < R (trochoid not touching the fixed circle).</li>
 * <li>Prolate cycloid: D > R (trochoid crossing the fixed circle).</li></ul>
 * <p>This class is considered a supplementary class to the
 * Public Domain HTML 3D Library and is not considered part of that
 * library. <p>
 * To use this class, you must include the script "extras/evaluators.js"; the
 * class is not included in the "h3du_min.js" file which makes up
 * the HTML 3D Library. Example:<pre>
 * &lt;script type="text/javascript" src="extras/evaluators.js">&lt;/script></pre>
 * @constructor
 * @augments H3DU.Curve
 * @param {number} radius Radius of the rolling circle.
 * @param {number} distFromCenter Distance from the center of the
 * rolling circle to the drawing pen.
 */
H3DU.Trochoid = function(radius, distFromCenter) {
  "use strict";
  this.inner = radius;
  this.distFromCenter = distFromCenter;
};
H3DU.Trochoid.prototype = Object.create(H3DU.Curve.prototype);
H3DU.Trochoid.prototype.constructor = H3DU.Trochoid;

/**
 * Generates a point on the curve from the given U coordinate.
 * @function
 * @param {number} u U coordinate.
 * @returns {Array<number>} A 3-element array specifying a 3D point.
 * Only the X and Y coordinates will be other than 0.
 */
H3DU.Trochoid.prototype.evaluate = function(u) {
  "use strict";
  var cosu = Math.cos(u);
  var sinu = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(u);
  return [
    this.inner * u - this.distFromCenter * sinu,
    this.inner - this.distFromCenter * cosu,
    0
  ];
};
/**
 * Gets the endpoints of this curve.
 * For this curve evaluator object, the curve
 * starts at 0 and ends at &pi;*2.
 * @function
 * @returns {Array<number>} An array containing the two
 * endpoints of the curve. The first number is the start of the curve,
 * and the second number is the end of the curve. *
 */
H3DU.Trochoid.prototype.endPoints = function() {
  "use strict";
  return [0, H3DU.Math.PiTimes2];
};
/**
 * Finds the velocity (derivative) of this curve at the given point.
 * @param {number} u Point on the curve to evaluate.
 * @returns {Array<number>} An array giving the velocity vector.
 */
H3DU.Trochoid.prototype.velocity = function(u) {
  "use strict";
  var cosu = Math.cos(u);
  var sinu = u >= 0 && u < 6.283185307179586 ? u <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(u);
  return [this.inner - this.distFromCenter * cosu,
    this.distFromCenter * sinu, 0];
};
/**
 * A [curve evaluator object]{@link H3DU.Curve} for a curve drawn by a circle that rolls along the outside
 * of another circle, whose position is fixed, with a center of (0,0).
 * The rolling circle will start at the positive X axis of the fixed circle.<p>
 * The following curves can be generated with this class (in the following
 * descriptions, O = <code>outerRadius</code>, R means <code>rollerRadius</code>,
 * and D = <code>distFromRollerCenter</code>).<ul>
 * <li>Epicycloid: D = R (epitrochoid touching the fixed circle).</li>
 * <li>Curtate epicycloid: D < R (epitrochoid not touching the fixed circle).</li>
 * <li>Prolate epicycloid: D > R (epitrochoid crossing the fixed circle).</li>
 * <li>Cardioid: R = O; D = O.</li>
 * <li>Nephroid: R = O/2; D = O/2.</li>
 * <li>Ranunculoid: R = O/5; D = O/5.</li>
 * <li>N-cusped epicycloid: R = O/N; D = O/N.</li>
 * <li>Circle: O = 0; the radius will be R - D.</li>
 * <li>Epicycloid: R = D.</li></ul>
 * <p>This class is considered a supplementary class to the
 * Public Domain HTML 3D Library and is not considered part of that
 * library. <p>
 * To use this class, you must include the script "extras/evaluators.js"; the
 * class is not included in the "h3du_min.js" file which makes up
 * the HTML 3D Library. Example:<pre>
 * &lt;script type="text/javascript" src="extras/evaluators.js">&lt;/script></pre>
 * @constructor
 * @augments H3DU.Curve
 * @param {number} outerRadius Radius of the circle whose position
 * is fixed.
 * @param {number} rollerRadius Radius of the rolling circle.
 * An epicycloid results when distFromRollerCenter=rollerRadius.
 * @param {number} distFromRollerCenter Distance from the center of the
 * rolling circle to the drawing pen.
 * @param {number} [rotationDegrees] Starting angle of the curve from the positive X axis toward the positive Y axis, in degrees. Default is 0.
 */
H3DU.Epitrochoid = function(outerRadius, rollerRadius, distFromRollerCenter, rotationDegrees) {
  "use strict";
  this.outer = outerRadius;
  this.roller = rollerRadius;
  this.distFromRoller = distFromRollerCenter;
  var phase = rotationDegrees || 0;
  phase = phase >= 0 && phase < 360 ? phase : phase % 360 +
       (phase < 0 ? 360 : 0);
  phase *= H3DU.Math.ToRadians;
  var cosPhase = Math.cos(phase);
  var sinPhase = phase <= 3.141592653589793 ? Math.sqrt(1.0 - cosPhase * cosPhase) : -Math.sqrt(1.0 - cosPhase * cosPhase);
  this.sinPhase = sinPhase;
  this.cosPhase = cosPhase;
};
H3DU.Epitrochoid.prototype = Object.create(H3DU.Curve.prototype);
H3DU.Epitrochoid.prototype.constructor = H3DU.Epitrochoid;

/**
 * Generates a point on the curve from the given U coordinate.
 * @function
 * @param {number} u U coordinate.
 * @returns {Array<number>} A 3-element array specifying a 3D point.
 * Only the X and Y coordinates will be other than 0.
 */
H3DU.Epitrochoid.prototype.evaluate = function(u) {
  "use strict";
  var oi = this.outer + this.roller;
  var term = oi * u / this.roller;
  var uangle = u;
  var cosu = Math.cos(uangle),
    sinu = uangle >= 0 && uangle < 6.283185307179586 ? uangle <= 3.141592653589793 ? Math.sqrt(1.0 - cosu * cosu) : -Math.sqrt(1.0 - cosu * cosu) : Math.sin(uangle);
  var cost = Math.cos(term),
    sint = term >= 0 && term < 6.283185307179586 ? term <= 3.141592653589793 ? Math.sqrt(1.0 - cost * cost) : -Math.sqrt(1.0 - cost * cost) : Math.sin(term);
  var x = oi * cosu - this.distFromRoller * cost;
  var y = oi * sinu - this.distFromRoller * sint;
  return [x * this.cosPhase - y * this.sinPhase,
    y * this.cosPhase + x * this.sinPhase, 0];

};
/**
 * Gets the endpoints of this curve.
 * For this curve evaluator object, the curve
 * starts at 0 and ends at &pi;*2.
 * @function
 * @returns {Array<number>} An array containing the two
 * endpoints of the curve. The first number is the start of the curve,
 * and the second number is the end of the curve. *
 */
H3DU.Epitrochoid.prototype.endPoints = function() {
  "use strict";
  return [0, H3DU.Math.PiTimes2];
};
/**
 * Creates a modified version of this curve so that it
 * fits the given radius.
 * @function
 * @param {number} radius Desired radius of the curve.
 * @returns {H3DU.Epitrochoid} Return value.
 */
H3DU.Epitrochoid.prototype.scaleTo = function(radius) {
  "use strict";
  var oi = this.outer + this.roller;
  var mx = Math.abs(Math.max(
    -oi - this.distFromRoller,
    -oi + this.distFromRoller,
    oi - this.distFromRoller,
    oi + this.distFromRoller));
  var ratio = radius / mx;
  return new H3DU.Epitrochoid(
    this.outer * ratio,
    this.roller * ratio,
    this.distFromRoller * ratio);
};

/* exported Hypotrochoid */
/**
 * Alias for the {@link H3DU.Hypotrochoid} class.
 * @constructor
 * @alias Hypotrochoid
 * @deprecated Use {@link H3DU.Hypotrochoid} instead.
 */
var Hypotrochoid = H3DU.Hypotrochoid;

/* exported Trochoid */
/**
 * Alias for the {@link H3DU.Trochoid} class.
 * @constructor
 * @alias Trochoid
 * @deprecated Use {@link H3DU.Trochoid} instead.
 */
var Trochoid = H3DU.Trochoid;

/* exported Epitrochoid */
/**
 * Alias for the {@link H3DU.Epitrochoid} class.
 * @constructor
 * @alias Epitrochoid
 * @deprecated Use {@link H3DU.Epitrochoid} instead.
 */
var Epitrochoid = H3DU.Epitrochoid;
